package lxs.swift.instance.action;


import lxs.swift.instance.Chain;
import lxs.swift.instance.StructInstance;
import lxs.swift.verify.Asserts;
import lxs.swift.verify.Verifies;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;


public class Action<Key, Value> {

    private final StructInstance<Key> instance;
    private final Function<Object, Value> convertor;

    public Action(StructInstance<Key> instance, Function<Object, Value> convertor) {
        this.instance = instance;
        this.convertor = convertor;
    }

    public Value get(Key key) {
        Object o = instance.of(key);
        return convertor.apply(o);
    }

    public Value read(String chainStr) {
        Chain chain = Chain.parse(chainStr);
        return read(chain);
    }

    public Value read(Chain chain) {
        return convertor.apply(chain.read(this.instance));
    }

    public void write(String chainStr, Value value) {
        Chain chain = Chain.parse(chainStr);
        chain.write(this.instance, value);
    }

    public void write(Chain chain, Value value) {
        chain.write(this.instance, value);
    }

    public void set(Key key, Value value) {
        instance.set(key, value);
    }

    public void setOr(Key key, Value value) {
        Object of = instance.of(key);
        if (of == null) instance.set(key, value);
    }


    public List<Value> values() {
        List<Value> values = new ArrayList<>();
        instance.iterate((k, v) -> values.add(this.convertor.apply(v)));
        return values;
    }

    public Value getOr(Key key, Value or) {
        Value v = get(key);
        if (v == null) {
            set(key, or);
            return or;
        }
        return v;
    }

    public boolean isNull(Key key) {
        Value v = get(key);
        return v == null;
    }

    public boolean isEqual(Key key, Value value) {
        Value v = get(key);
        return Verifies.isObjectEq(v, value);
    }

    public Optional<Value> optional(Key key) {
        return Optional.ofNullable(get(key));
    }


    @SafeVarargs
    public final List<Value> values(Key... keys) {
        List<Value> list = new ArrayList<>();
        for (Key key : keys) {
            list.add(get(key));
        }
        return list;
    }


}
